package net.pws.common.persistence.jdbc;

import java.sql.Connection;

import javax.sql.DataSource;

import net.pws.common.persistence.DataSourceAware;
import net.pws.common.persistence.QueryStatementManager;
import net.pws.common.persistence.QueryStatementManagerAware;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.support.DaoSupport;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.support.SQLExceptionTranslator;


public class JdbcDaoSupportOracleExtension extends DaoSupport implements
                                                             DataSourceAware,
                                                             QueryStatementManagerAware {
    
    static final Log log = LogFactory.getLog(JdbcDaoSupportOracleExtension.class);
    
    protected JdbcTemplateOracleExtension jdbcTemplate;
    
    protected QueryStatementManager queryStatementManager;
    
    public QueryStatementManager getQueryStatementManager() {
        return queryStatementManager;
    }
    
    /**
     * @spring.property ref = "sqlStatementManagementBean"
     * @param sqlStatementManagementBean
     */
    public void setQueryStatementManager(QueryStatementManager queryStatementManager) {
        this.queryStatementManager = queryStatementManager;
    }
    
    protected String getNamedStatement(String statementName) {
        if (log.isDebugEnabled()) {
            log.debug("statement name:" + statementName);
        }
        String result = null;
        if (queryStatementManager != null) {
            result = queryStatementManager.getStatementByName(statementName);
            result = (result != null) ? result.trim() : result;
        }
        if (log.isDebugEnabled()) {
            log.debug("statement value:" + result);
        }
        return result;
    }
    
    /**
     * Set the JDBC DataSource to be used by this DAO.
     * 
     * @spring.property ref = "dataSource"
     */
    public final void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = createJdbcTemplate(dataSource);
    }
    
    /**
     * Create a JdbcTemplate for the given DataSource. Only invoked if
     * populating the DAO with a DataSource reference!
     * <p>
     * Can be overridden in subclasses to provide a JdbcTemplate instance with
     * different configuration, or a custom JdbcTemplate subclass.
     * 
     * @param dataSource
     *            the JDBC DataSource to create a JdbcTemplate for
     * @return the new JdbcTemplate instance
     * @see #setDataSource
     */
    protected JdbcTemplateOracleExtension createJdbcTemplate(DataSource dataSource) {
        return new JdbcTemplateOracleExtension(dataSource);
    }
    
    /**
     * Return the JDBC DataSource used by this DAO.
     */
    public final DataSource getDataSource() {
        return (this.jdbcTemplate != null ? this.jdbcTemplate.getDataSource()
                                         : null);
    }
    
    /**
     * Set the JdbcTemplate for this DAO explicitly, as an alternative to
     * specifying a DataSource.
     */
    public final void setJdbcTemplate(JdbcTemplateOracleExtension jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    
    /**
     * Return the JdbcTemplate for this DAO, pre-initialized with the DataSource
     * or set explicitly.
     */
    public final JdbcTemplateOracleExtension getJdbcTemplate() {
        return jdbcTemplate;
    }
    
    protected final void checkDaoConfig() {
        if (this.jdbcTemplate == null) {
            throw new IllegalArgumentException("dataSource or jdbcTemplate is required");
        }
    }
    
    /**
     * Get a JDBC Connection, either from the current transaction or a new one.
     * 
     * @return the JDBC Connection
     * @throws org.springframework.jdbc.CannotGetJdbcConnectionException
     *             if the attempt to get a Connection failed
     * @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection(javax.sql.DataSource)
     */
    protected final Connection getConnection() throws CannotGetJdbcConnectionException {
        return DataSourceUtils.getConnection(getDataSource());
    }
    
    /**
     * Return the SQLExceptionTranslator of this DAO's JdbcTemplate, for
     * translating SQLExceptions in custom JDBC access code.
     * 
     * @see org.springframework.jdbc.core.JdbcTemplate#getExceptionTranslator
     */
    protected final SQLExceptionTranslator getExceptionTranslator() {
        return this.jdbcTemplate.getExceptionTranslator();
    }
    
    /**
     * Close the given JDBC Connection, created via this DAO's DataSource, if it
     * isn't bound to the thread.
     * 
     * @deprecated in favor of releaseConnection
     * @see #releaseConnection
     */
    protected final void closeConnectionIfNecessary(Connection con) {
        releaseConnection(con);
    }
    
    /**
     * Close the given JDBC Connection, created via this DAO's DataSource, if it
     * isn't bound to the thread.
     * 
     * @param con
     *            Connection to close
     * @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
     */
    protected final void releaseConnection(Connection con) {
        DataSourceUtils.releaseConnection(con, getDataSource());
    }
    
}
